#pragma once
#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>


#define defaultip "0.0.0.0"
#define defaulport 8080
class Server
{
public:
    //typedef std::function<void (std::string,uint16_t,std::string) > fun_t;
    typedef void(*fun_t)(std::string,uint16_t,std::string);

    enum{SOCKETFD_ERRNO = 1,SOCKETBIND_ERRNO = 2,RECVFROM_ERRNO = 3};
                                                        
    Server(const fun_t& callback,const uint16_t port , const std::string& ip = defaultip)
    :_port(port), _ip(ip),_socketfd(-1),_callback(callback)
    {}

    void initServer()
    {
          //创建网络udp文件
          _socketfd = socket(AF_INET,SOCK_DGRAM,0);
          
          if(_socketfd == - 1)
          {
              std::cout << errno << strerror(errno) << std::endl;
              exit(1);
          }
          std::cout << "socket sucess:" << _socketfd << std::endl;
          // 开始正式建立连接
          struct sockaddr_in address;
          bzero(&address,sizeof(address));
          address.sin_family = AF_INET;
          //转为网络大端数据
          address.sin_port = htons(_port);
          //inet_addr可以把 string -> char* -> 网络数据，可谓是一步到位
          //address.sin_addr.s_addr = inet_addr(_ip.c_str());
          //真正的开发都链接的是零地址
          address.sin_addr.s_addr = htonl(INADDR_ANY);
          //填充这个结构图异常重要
          int ret = bind(_socketfd,(struct sockaddr*)&address,sizeof address);
        //  std::cout << "ret ==" << ret << std::endl;s
          if(ret == -1)
          {
            std::cout << errno << strerror(errno) << std::endl;
            exit(2);
          }
          
    }

    void start()
    {
        //开始从网络里读数据
        char buffer[1024];
        for(;;)
        {
            struct sockaddr_in address;
            socklen_t len = sizeof(address);
            //已经把客户端的消息读出来了
            ssize_t ret = recvfrom(_socketfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&address,&len);
            //std::cout << "ret == " << ret << std::endl;
            // if(ret == -1)
            // {
            //     std::cout << errno << strerror(errno) << std::endl;
            //     exit(3);
            // }
            
            if(ret > 0)
            {
                buffer[ret] = 0;
                std::string consumerip = inet_ntoa(address.sin_addr);
                uint16_t consumerport = ntohs(address.sin_port);

                std::string message = buffer;

                std::cout << consumerip << "["  << consumerport << "]#" << message << std::endl;

                _callback(consumerip,consumerport,message);

            }

        }
    }

   

private:
   // 服务器需要ip和端口号
   std::string _ip;
   uint16_t _port;
   int _socketfd;
   fun_t _callback;
};

